#include "stdafx.h"

#include "ConnectionManager.h"

#ifdef _WIN32
#ifdef _DEBUG
	#define _CRTDBG_MAP_ALLOC
	#include <stdlib.h>
	#include <crtdbg.h>
	#undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
	#define new       new( _NORMAL_BLOCK, __FILE__, __LINE__)
	#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif


namespace tlnet {

// Constructor
ConnectionManager::ConnectionManager(HANDLE hReady) {
	this->mutex = CreateMutex(NULL, FALSE, LPCTSTR("NetworkManager"));
	this->hReady = hReady;

	this->head = this->curr = NULL;
}

// Deconstructor
ConnectionManager::~ConnectionManager() {
	Connection *slider;
	Connection *tmp;

	// close standard connections
//	printf("A\n");
	slider = this->head;
	while(slider != NULL) {
		// remember pointer and advance to next
		tmp = slider;
		slider = slider->next;

		// avoid closing server connections for now
		if(tmp->settings.isSet("isListen")) {
			// skip server sockets for now
			continue;
		}

		// delete the connection
		this->del(tmp);
	}

	// close listen connections
//	printf("B\n");
	slider = this->head;
	while(slider != NULL) {
		// remember pointer and advance to next
		tmp = slider;
		slider = slider->next;

		// listen connections must be closed
		printf("closing listen socket\n");
		closesocket(slider->socket);

		// delete the connection
		this->del(tmp);
	}

//	printf("C\n");

	CloseHandle(this->mutex);
}


// Add a new Connection
Connection* ConnectionManager::add() {
	Connection *slider = this->head;

	// This will be the first Connection
	if(slider == NULL) {
		this->head = new Connection(this->mutex, this->hReady);
		this->head->prev = NULL;
		this->head->next = NULL;

		slider = this->head;
	}
	// Not the first Connection, add to end of list
	else {
		// advanced till slider is the last node
		while(slider->next != NULL) {
			slider = slider->next;
		}
		// At end of list, attach new Connection
		slider->next = new Connection(this->mutex, this->hReady);
		slider->next->prev = slider;
		slider->next->next = NULL;

		slider = slider->next;
	}

	// set initial values

	// Return a pointer to the new Connection
	return slider;
}

// Del the specified Connection
bool ConnectionManager::del(Connection *conn) {
	Connection *slider = this->head;
//	DWORD lpExitCode;

	if(slider == NULL) {
		return false;
	}

	while(slider != NULL) {
		if(slider == conn) {
			break;
		}
		slider = slider->next;
	}

	if(slider == NULL) {
		return false;
	}

	if(slider == this->head) {
		this->head = slider->next;
		if(this->head != NULL) {
			this->head->prev = NULL;
		}
	}
	else {
		if(slider->prev != NULL) {
			slider->prev->next = slider->next;
		}
		if(slider->next != NULL) {
			slider->next->prev = slider->prev;
		}
	}

	// adjust curr if necessary
	if(this->curr == slider) {
		this->curr = slider->next;
	}

	// free up resources
	delete slider;

	return true;
}


// used to loop through the connections
Connection* ConnectionManager::getNext() {
	Connection *slider = this->curr;

	if(this->curr != NULL) {
		this->curr = this->curr->next;
	}

	return slider;
}

// reset getNext() back to first node
void ConnectionManager::reset() {
	this->curr = this->head;
}

}